// --- Copyright (c) 2006-2008 Stefan Kyntchev ---
// This software is written and copyrighted by Stefan Kyntchev 
// and BeyondPod Team members. All rights are reserved.
// Author contact: support@beyondpod.mobi
// ------------------------------------------------------------------------
// This file is part of BeyondPod RSS Feed Reader and Podcast manager
// (www.codeplex.com/BeyondPod) 
// BeyondPod is free software: you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation, either version 3 of the License, or 
// (at your option) any later version. 
//  
// BeyondPod is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more details. 
//  
// You should have received a copy of the GNU General Public License
// along with BeyondPod. If not, see <http://www.gnu.org/licenses/>
// ------------------------------------------------------------------------
// COPYRIGHT NOTICE: This copyright notice may NOT be removed, obscured or modified 
// without written consent from the author.
// --- End copyright notice --- 


using System;
using System.Collections.Generic;
using System.Windows.Forms;
using svs.Mobile.BeyondMedia.FeedCore;
using svs.Mobile.BeyondMedia.FeedCore.Helpers;
using svs.Mobile.BeyondMedia.FeedCore.Properties;
using svs.Mobile.BeyondMedia.FeedCore.RSS;

namespace svs.Mobile.BeyondMedia.FeedCore.RSS
{
	public class RssFeedUpdateManager
	{
		public delegate void UpdateEvent();
		public delegate void FeedChangedEvent(Feed feed);
	
		private static readonly RSSFeedCatcher m_Catcher = new RSSFeedCatcher();
		private static readonly Queue<Feed> m_UpdateQueue = new Queue<Feed>();
		private static bool m_AtQueueStart = false;

		private static readonly DownloadStatisticsList _UpdateStatistics = new DownloadStatisticsList();

		public static event UpdateEvent UpdateCompleted;
		public static event UpdateEvent UpdateCanceled;
		public static event UpdateEvent UpdateStarting;
		public static event FeedChangedEvent FeedChanged;
		public static event FeedChangedEvent FeedUpdateProgress;

		#region Public Methods

		static RssFeedUpdateManager()
		{
			m_Catcher.FeedDownloaded += OnFeedDownloaded;
			m_Catcher.FeedUpdateStarted += OnFeedUpdateStarted;
			m_Catcher.FeedUpdateError += OnFeedUpdateError;
			m_Catcher.FeedUpdateTerminated += OnFeedUpdateStatusChanged;
			m_Catcher.FeedUpdateProgress += OnFeedUpdateProgress;
		}

		public static void UpdateFeeds(FeedList todownload)
		{
			if(!PrepareForUpdate())
				return;

			foreach (Feed f in todownload)
			{
				m_UpdateQueue.Enqueue(f);
			}

			UpdateQueuedFeeds();
		}

		public static void TerminateAllUpdates()
		{
			if (m_Catcher.IsUpdating)
				m_Catcher.Stop();

			if (m_UpdateQueue.Count > 0)
			{
				m_UpdateQueue.Clear();
			}

			if (UpdateCanceled != null)
				UpdateCanceled();
		}

		#endregion

		#region Public Properties

		//True if the current download is the first download for the queue
		public static bool IsAtQueueStart
		{
			get
			{
				return m_AtQueueStart;
			}
		}

		public static bool IsUpdating
		{
			get
			{
				return m_Catcher.IsUpdating;
			}
		}

		public static int QueueCount
		{
			get
			{
				return m_UpdateQueue.Count;
			}
		}

		/// <summary>
		/// The feed that is being currently updated
		/// </summary>
		public static Feed CurrentFeed
		{
			get
			{
				return m_UpdateQueue.Count == 0 ? null : m_UpdateQueue.Peek();
			}
		}

		/// <summary>
		/// Statistics for the last update
		/// </summary>
		public static DownloadStatisticsList Statistics
		{
			get { return _UpdateStatistics; }
		}

		#endregion

		#region Private Methods

		private static void UpdateFeedInternal(Feed feed)
		{
			if (feed == null || !feed.HasUrl)
			{
				throw new ArgumentException("Error updating feed: both Feed and Feed.URL are required parameters");
			}

			if (UpdateStarting != null)
				UpdateStarting();
			
			m_Catcher.InitializeCatcher(feed);
			m_Catcher.UpdateFeed(false);

		}

		private static bool PrepareForUpdate()
		{
			FlashStorageLocation loc = new FlashStorageLocation(Configuration.RssCachePath);

			if (!CoreHelper.IsDeviceConnected())
			{
				MessageBox.Show(Resources.DeviceNotConnectedMsg, Resources.DeviceNotConnectedTitle,
												MessageBoxButtons.OK,
												MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
				return false;
			}

			if (m_Catcher.IsUpdating || EnclosureDownloadManager.IsDownloading)
			{
				MessageBox.Show(Resources.AnotherDownloadInProgressMsg, Resources.AnotherDownloadInProgressTitle,
				                MessageBoxButtons.OK,
				                MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
				return false;
			}
			else if(loc.CheckIfSpaceIsAvailable(200 * 1024) == false)
			{
				MessageBox.Show(
						string.Format(Resources.IssuficientStorageSpaceMsg,
													loc.AvailableSpaceAsString, loc.FriendlyLocationName, "200 K"), Resources.IssuficientStorageSpaceTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
				return false;
			}
			else
			{
				m_UpdateQueue.Clear();
				m_AtQueueStart = true;
				return true;
			}
		}

		private static void UpdateQueuedFeeds()
		{
			if (CurrentFeed != null)
			{
				UpdateFeedInternal(CurrentFeed);
			}
			else
			{
				OnUpdateBatchCompleted();
			}
		}

		static void OnFeedUpdateError(Feed aFeed, Exception ex)
		{
			OnFeedChanged(aFeed);
			UpdateStatistics(aFeed);

			if (ex is CoreHelper.UnableToEstablishNetworkConnectionException)
				TerminateAllUpdates();
			else
        DoNextFeed();
		}

		static void OnFeedUpdateStarted(Feed aFeed)
		{
			if(IsAtQueueStart)
				OnUpdateBatchStarted();

			OnFeedChanged(aFeed);
		}

		static void OnUpdateBatchStarted()
		{
			CoreHelper.WriteTraceEntry("Update Batch Started!");
			_UpdateStatistics.Clear();
			_UpdateStatistics.DownloadTime = DateTime.Now;
		}

		private static void OnFeedUpdateProgress(Feed aFeed)
		{
			if (FeedUpdateProgress != null)
				FeedUpdateProgress(aFeed);
		}

		static void OnUpdateBatchCompleted()
		{
			CoreHelper.WriteTraceEntry("Update Batch Completed!");

			if (Configuration.FeedsSortOrder == CoreHelper.SortOrder.ByDateAsc || Configuration.FeedsSortOrder == CoreHelper.SortOrder.ByDateDesc)
			{
				FeedRepository.SortFeeds(FeedRepository.RootFeed);
			}

			if (UpdateCompleted != null)
				UpdateCompleted();
		}

		static void OnFeedUpdateStatusChanged(Feed aFeed)
		{
			OnFeedChanged(aFeed);
		}

		static void OnFeedDownloaded(Feed aFeed)
		{
			OnFeedChanged(aFeed);
			UpdateStatistics(aFeed);
			DoNextFeed();
		}

		private static void DoNextFeed()
		{
			if (m_UpdateQueue.Count > 0)
			{
				m_UpdateQueue.Dequeue();
				m_AtQueueStart = false;
			}
			UpdateQueuedFeeds();
		}

		private static void UpdateStatistics(Feed aFeed)
		{
			if (m_Catcher.Statistics != null)
				m_Catcher.Statistics.OwnerFeed = aFeed;

			_UpdateStatistics.Add(m_Catcher.Statistics);
		}

		static void OnFeedChanged(Feed aFeed)
		{
			if(FeedChanged != null)
			{
				FeedChanged(aFeed);
			}
		}

		#endregion
	}
}